﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IrrlichtLime;
using IrrlichtLime.Core;
using IrrlichtLime.Scene;

namespace BillardPHS4700 {

    enum ControlType {
        PlacingMode,
        SimulationMode
    }

    class Interface {
        Engine m_engine;
        Simulation m_simulation;
        /// <summary>
        /// The ball being dragged, null if no drag is in progress
        /// </summary>
        SceneNode m_ballBeingDragged;
        bool m_lastLMB;

        public event EventHandler Shoot;

        public Interface(Engine engine, Simulation simulation) {
            m_engine = engine;
            m_simulation = simulation;
        }

        public void SwitchMode(ControlType ct) {
            if (ct == ControlType.PlacingMode) {
                m_engine.OnEvent += OnEventPlacingMode;
                m_engine.OnEvent -= OnEventSimulationMode;
            }
            else {
                m_engine.OnEvent -= OnEventPlacingMode;
                m_engine.OnEvent += OnEventSimulationMode;
            }
        }

        bool OnEventSimulationMode(Event evnt) {
            switch (evnt.Type) {
                case EventType.Key:
                    var key = evnt.Key.Key;
                    var pressedDown = evnt.Key.PressedDown;
                    if (pressedDown && (key == KeyCode.PageDown || key == KeyCode.PageUp)) {
                        m_simulation.TimeStep *= key == KeyCode.PageDown ? 0.8f : 1.25f;
                    }
                    break;
            }
            return false;
        }

        bool OnEventPlacingMode(Event evnt) {
            switch (evnt.Type) {
                case EventType.Key:
                    var key = evnt.Key.Key;
                    var pressedDown = evnt.Key.PressedDown;
                    // switch camera
                    if (pressedDown && key == KeyCode.KeyP) {
                        m_engine.ActiveCamera = m_engine.ActiveCamera == CameraType.Side ? 
                            CameraType.TopDown : 
                            CameraType.Side;
                        // Also reset queue height to that of the ball
                        var p = m_engine.CueStick.Position;
                        m_engine.CueStick.Position = new Vector3Df(p.X, p.Y, 0);
                    }
                    // rotate queue
                    if (pressedDown && (key == KeyCode.Left || key == KeyCode.Right)) {
                        var r = m_engine.WhiteBallRoot.Rotation;
                        r = new Vector3Df(r.X, r.Y, (r.Z + (key == KeyCode.Left ? -2f : 2f)) % 360f);
                        m_engine.WhiteBallRoot.Rotation = r;
                    }
                    // when in side view, move queue up and down
                    if (m_engine.ActiveCamera == CameraType.Side && pressedDown && (key == KeyCode.Up || key == KeyCode.Down)) {
                        var p = m_engine.CueStick.Position;
                        m_engine.CueStick.Position = new Vector3Df(p.X, p.Y, 
                            Utils.Clamp(p.Z + (key == KeyCode.Up ? 0.5f : -0.5f), -Constants.BallRadius + 1f, Constants.BallRadius - 1f));
                    }
                    // move queue back for shot
                    if (pressedDown && key == KeyCode.Space) {
                        m_engine.CueStick.Position += new Vector3Df(0, -0.3f, 0);
                    }
                    // if user releases space, shoot
                    if (!pressedDown && key == KeyCode.Space) {
                        if (Shoot != null) {
                            //while ((m_engine.CueStick.Position - m_engine.WhiteBallRoot.Position).Length > Constants.BallRadius)
                            //{
                            //   Console.WriteLine((m_engine.CueStick.Position - m_engine.WhiteBallRoot.Position).Length);
                            //    Console.WriteLine(Constants.BallRadius);
                            //    m_engine.CueStick.Position -= new Vector3Df(0, -0.1f, 0);
                            //    Console.WriteLine(m_engine.CueStick.Position);
                            //}
                            Shoot(this, null);
                        }
                    }
                    break;
                case EventType.Mouse: 
                    var mousePosition = new Vector2Di(evnt.Mouse.X, evnt.Mouse.Y);

                    if (evnt.Mouse.IsLeftPressed()) {
                        // If this is a new click
                        if (!m_lastLMB) {

                            // If we're in top-down view
                            if (m_engine.ActiveCamera == CameraType.TopDown) {
                                // check if it's on a ball
                                //TODO GetSceneNodeFromScreenCoordinatesBB seems finnicky; code something more reliable
                                var node = m_engine.CollisionManager.GetSceneNodeFromScreenCoordinatesBB(mousePosition);
                                if (0 <= node.ID && node.ID <= 14) {
                                    m_ballBeingDragged = m_engine.Balls[node.ID];
                                }
                                // If this is the white ball visual node, drag its root
                                if (node.ID == 15) {
                                    m_ballBeingDragged = m_engine.WhiteBallRoot;
                                }
                            }
                        }
                        else {
                            // a drag is in progress
                            if (m_engine.ActiveCamera == CameraType.TopDown && m_ballBeingDragged != null) {
                                var plane = new Plane3Df(m_ballBeingDragged.Position, new Vector3Df(0, 0, 1));
                                var ray = m_engine.CollisionManager.GetRayFromScreenCoordinates(mousePosition);
                                Vector3Df intersection;
                                plane.GetIntersectionWithLine(ray.Start, ray.Vector, out intersection);
                                m_ballBeingDragged.Position = intersection;
                            }
                        }
                    }
                    else {
                        m_ballBeingDragged = null;
                    }

                    m_lastLMB = evnt.Mouse.IsLeftPressed();
                    break;
            }

            return false;
        }
    }
}
